package apibasej.basic.thread;

import java.util.logging.Level;

import apibasej.basic.InterfaceExec;
import apibasej.basic.pool.APIBasePoolException;
import apibasej.basic.pool.ItemPool;


public class PooledThread extends ItemPool{

	private Thread thread;
	private InterfaceExec exec;
	
	private int idThread;
	private static int ctThread = 0;

	private Status status = Status.NEW;
	
	public enum Status{NEW,CREATING_THREAD,STARTED,WAITING,EXECUTING,INVALIDATED}
	
	private SimpleThreadPool pool;
	
	public PooledThread(SimpleThreadPool pool) {
		this.pool = pool;
	}
	
	
	private synchronized Thread getThread() {
		if(thread==null){
			idThread = ++ctThread;
			status = Status.CREATING_THREAD;
			thread = new Thread(){
				@Override
				public void run() {
					status = Status.STARTED;
					//TestThreadPool.incTotalRun();
					try {
						while(true){
							if(exec==null){
								status = Status.WAITING;
								synchronized (thread) {
									// verifica de novo se o exec está null, pois pode ter ficado null entre a primeira verificação e o wait
									if(exec==null) thread.wait(10000);// espera no máximo 10 segundos, depois roda o loop denovo
								}
							}else{
								status = Status.EXECUTING;
								try{
									exec.exec();// executa
								}catch (Throwable e) { // trata para não matar a thread ... só irá ter erro se tiver um RuntimeException ...
									logDef(Level.SEVERE,"[PooledThread] Error on execute item in PooledThread",e);
								}finally{
									exec = null;
									status = Status.WAITING;
									release();// libera este objeto do pool
								}
							}
							if(isInvalidated()) {
								status = Status.INVALIDATED;
								break;
							}
						}
					} catch (InterruptedException e) {
						logDef(Level.SEVERE,"[PooledThread] InterruptedException in PooledThread",e);
					}
					if(!isInvalidated()) {
						invalidate();
					}
				}
			};
			//TestThreadPool.incTotalStart();
			thread.start();
		}
		return thread;
	}
	
	public synchronized void execute(final InterfaceExec exec) throws APIBasePoolException{
		if(Status.EXECUTING.equals(status)) throw new APIBasePoolException("This thread is busy!");
		Thread t = getThread();// somente para criar um pouco antes ...
		synchronized(t) {
			this.exec = exec;
			t.notify();
		}
	}
	
	@Override
	public void invalidate() {
		super.invalidate();
		this.exec = null;
		Thread t = getThread();
		synchronized(t) {// para liberar a thread
			t.notify();
		}
	}
	
	
	public InterfaceExec getExec() {
		return exec;
	}
	public Status getStatus() {
		return status;
	}
	public int getIdThread() {
		return idThread;
	}
	
	public SimpleThreadPool getPool() {
		return pool;
	}
}
